package cn.goour.web.base.handler

import cn.goour.web.base.entity.Msg
import cn.goour.web.base.exception.BackJsonBeanValidFailException
import com.alibaba.fastjson.JSONObject
import isAjax
import org.slf4j.LoggerFactory
import org.springframework.dao.DataIntegrityViolationException
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseBody
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import javax.validation.ConstraintViolationException
import javax.validation.UnexpectedTypeException
import javax.validation.ValidationException

@ControllerAdvice
open class MyExceptionHandler {

    @ExceptionHandler(Exception::class)
    @ResponseBody
    open fun handle(request: HttpServletRequest, response: HttpServletResponse, e: Exception) {
        e.printStackTrace()
        println(e.javaClass.name)
        logger.error("捕捉到全局错误", e)
        logger.info("ajax=${request.isAjax()}")
        logger.info("意外的错误：$e${e.message}")

        if (request.isAjax()) {
            val msg = Msg.error("意外的错误：${e.message}")
            val json = JSONObject.toJSONStringWithDateFormat(msg, "yyyy-MM-dd HH:mm:ss")
            response.characterEncoding = "utf-8"
            response.contentType = "application/json;charset=UTF-8"
            response.writer.print(json)
            response.writer.flush()
        } else {
            response.sendRedirect(request.contextPath + "/404.html")
        }

    }

    /**
     * 更新数据库数据的时候错误，主要问题是字段内容超过字段设置长度导致，以及类型不正确等问题
     */
    @ExceptionHandler(DataIntegrityViolationException::class)
    @ResponseBody
    open fun dataIntegrityViolationException(e: Exception): Msg {
        logger.error("数据库操作错误", e)
        return when (e) {
            is DataIntegrityViolationException -> Msg(1, "操作数据库数据失败", arrayOf("内容格式不正确", "内容超过长度", "其他未知问题"))
            else -> Msg(1, "未知错误", arrayOf(e.message))
        }
    }

    /**
     * 捕获请求参数Bean验证异常和保存数据库时验证异常
     */
    @ResponseBody
    @ExceptionHandler(BackJsonBeanValidFailException::class, ValidationException::class)
    open fun backJsonBeanValidFailException(e: Exception): Msg {
        e.printStackTrace()
        logger.error("参数校验失败",e)
        return when (e) {
            is BackJsonBeanValidFailException -> Msg(e.code, e.message, e.msgs)
            is ConstraintViolationException -> {
                val list = arrayListOf<String>()
                e.constraintViolations.forEach {
                    list.add(it.message)
                }
                Msg(1, "请求参数校验失败", list.toTypedArray())
            }
            is UnexpectedTypeException -> {
                Msg(1, "请求参数校验失败", arrayOf("参数类型转换失败", "参数类型不正确","此项一般为程序错误，请联系管理员和复现错误"))
            }
            is ValidationException -> {
                Msg(1, "请求参数校验失败", arrayOf("参数验证其他未知错误，请检查参数是否合法和类型是否正确"))
            }
            else -> Msg(1, "未知错误", arrayOf(e.message))
        }
    }

    companion object {
        private val logger = LoggerFactory.getLogger(MyExceptionHandler::class.java)
    }
}